home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Toolbox / Visual Basic Toolbox (P.I.E.)(1996).ISO / patchfix / ddefix / ddefix.txt
Encoding:
Internet Message Format  |  1995-06-29  |  16.6 KB

  1. Date:  06/29/95
  2. RE:    Correction for program group and item creation
  3. Author: Todd Hardin  with many contributions from Gregg S. Irwin
  4.  
  5.  
  6. Description of problem:
  7.     When attempting to create a program group using an existing
  8.     group file name, but a different group name, program manager
  9.     fails silently (or at least there doesn't seem to be a way
  10.     to communicate sucess via DDE with progman.exe).
  11.     The result is that the program manager group with focus is the
  12.     last group the user had given focus to before running your 
  13.     setup program.  Since the AddItem command simply add the item to
  14.     the group with focus, your icons end up in unexpected places.
  15.  
  16. Example of problem:
  17.     Feb 1, 1995 - Client runs setup program.  group name is "Dog Group"
  18.                   Group file name is "DOG.GRP"
  19.  
  20.     Mar 1, 1995 - Clever person decides to change "Dog Group" to
  21.                   "Cat Group" but leave the file name alone.
  22.  
  23.     Apr 1, 1995 - Client recieves upgrade from you. When they run the 
  24.                   setup they are surprised to find you icons have
  25.                   been placed in "Main Group" (or some other group).
  26.  
  27. Solution:
  28.     I Should give credit to Gregg S. Irwin for providing examples of
  29.     how to retrieve information about groups and group contents.
  30.     I downloaded DDEPM.ZIP from the MSBASIC forum and found it 
  31.     instructive.  Note that I "borrowed" a few functions from
  32.     his code, however there may be a few alterations, so please
  33.     examine closely if you intend to add his routines to your 
  34.     setup in addition to this code from me.
  35.  
  36.     Logic - Check to see if there already exists a group with the
  37.             name I wish to use.  If so then I may move on to
  38.             adding items.
  39.  
  40.             Check to see if there already exists a group file with
  41.             the same file name I wish to use. (Note that I strip
  42.             off the path, so I don't care where the file resides. This
  43.             may not be the best assumption). If there is a group file
  44.             with my desired filename then retrieve the actual Group Name
  45.             text and use it to add items.
  46.  
  47.             OK, I know there is not a pre-existing group that I am
  48.             interested in, so it's safe to create my new group.
  49.  
  50. Disclaimer & Appology:
  51.     Use at your own risk.  This code is still a bit loose.  I was short
  52.     on time and have not added robust error handling. Naming convention
  53.     may be awkward from "borrowing" code from several sources.
  54.     If you clean this up, please post.
  55.  
  56.  
  57. '----------------------------------------------------------------------
  58. '>> Important! Remove the setup1.Label and replace with txtLink textbox control
  59. '   A text box can hold a much longer string than a label's caption.
  60. '   In retrieving lists of groups and lists of group contents some
  61. '   strings can get very long.
  62. '----------------------------------------------------------------------
  63.  
  64.  
  65. '----------------------------------------------------------------------
  66. '>> Add this to CreateProgManItem just before the ReplaceItem statement.    
  67. '   These two ShowGroup commands are necessary to ensure that our group
  68. '   has focus so it will receive the items icon.  Commands as per
  69. '   KB Article Q104943 - @:tlh
  70.     mtxtDDELink.LinkExecute "[ShowGroup(" + grpName$ + ",2)]"
  71.     mtxtDDELink.LinkExecute "[ShowGroup(" + grpName$ + ",1)]"
  72. '----------------------------------------------------------------------
  73.  
  74.  
  75. '----------------------------------------------------------------------
  76. '>> Add to Setup1A.FRM  Declarations section:
  77. Dim mtxtDDELink As TextBox  'TextBox for DDE communication
  78. Dim groupName$  'Group name to use with program manager
  79. Dim groupFile$  'Group file name to use with program manager
  80. Const DEFAULTGROUPNAME = "My App Group Title"
  81. Const DEFAULTGROUPFILE = "MYAPP"
  82. '----------------------------------------------------------------------
  83.  
  84.  
  85. '----------------------------------------------------------------------
  86. '>> Place near top of Setup1A.FRM  Form_Load
  87. Set mtxtDDELink = Setup1!txtLink  'Text box used for DDE communication
  88. groupName$ = DEFAULTGROUPNAME$
  89. groupFile$ = DEFAULTGROUPFILE$
  90. '----------------------------------------------------------------------
  91.  
  92.  
  93. '----------------------------------------------------------------------
  94. '>> Modify the section of setup1.frm  form_load that creates 
  95. '   program manager groups and items as follows:
  96. '
  97. '--------------------------------------
  98. ' Create program manager group and icon
  99. '--------------------------------------
  100. If Not (ddeChooseGroup%(mtxtDDELink, groupName$, groupFile$)) Then
  101.    GoTo ErrorSetup
  102. End If
  103. CreateProgManGroup mtxtDDELink, groupName$, groupFile$
  104. CreateProgManItem mtxtDDELink, destpath$ + "MYAPP1.EXE", "My App Name 1", groupName$
  105. CreateProgManItem mtxtDDELink, destpath$ + "MYAPP2.EXE", "My App Name 2", groupName$
  106. CreateProgManItem mtxtDDELink, destpath$ + "MYAPP3.EXE", "My App Name 3", groupName$
  107. CreateProgManItem mtxtDDELink, destpath$ + "MYAPP4.EXE", "My App Name 4", groupName$
  108. '----------------------------------------------------------------------
  109.  
  110.  
  111.  
  112. '----------------------------------------------------------------------
  113. '>> Create a new BAS file (I called mine, creatively enough, DDE.BAS)
  114. '----------------------------------------------------------------------
  115. '>>>>>>>>>>>>>>>>>>>>>>>Begin DDE.BAS
  116. Option Explicit
  117. DefInt A-Z
  118.  
  119. ' Used by myParseString
  120. Global Const ERR_ITEMS_TRUNCATED = -2
  121.  
  122. ' LinkMode (forms and controls)
  123. Global Const LINK_NONE = 0      ' 0 - None
  124. Global Const LINK_SOURCE = 1    ' 1 - Source (forms only)
  125. Global Const LINK_AUTOMATIC = 1 ' 1 - Automatic (controls only)
  126. Global Const LINK_MANUAL = 2    ' 2 - Manual (controls only)
  127. Global Const LINK_NOTIFY = 3    ' 3 - Notify (controls only)
  128.  
  129.  
  130. Function ddeChooseGroup% (mtxtDDELink As TextBox, grpName$, grpFile$)
  131.    Dim i%
  132.    Dim GetGroups%
  133.    Dim retcode%
  134.    ReDim arrGroups$(0)       'array of group names
  135.    ReDim arrGroupFiles$(0)   'array of group file names (w/o paths)
  136.  
  137.    On Error GoTo ErrddeChooseGroup
  138.  
  139.  
  140.    retcode% = ddepmGetGroups(mtxtDDELink, arrGroups$())
  141.    '
  142.    retcode% = ddepmGetGroupFiles%(mtxtDDELink, arrGroups$(), arrGroupFiles$())
  143.    '
  144.    retcode% = ddeSetGroupNameToUse%(arrGroups$(), arrGroupFiles$(), grpName$, grpFile$)
  145.    '
  146.    ddeChooseGroup% = True
  147.  
  148. Exit Function
  149.  
  150. ErrddeChooseGroup:
  151.    MsgBox "Error in retrieving information about program manager groups." & Chr$(10) & Chr$(13) & "Error Number: " & Str$(Err) & Chr$(10) & Chr$(13) & Error$
  152.    Exit Function
  153.  
  154.  
  155. End Function
  156.  
  157.  
  158. Private Function ddeParseString% (StringIn$, arrOut$(), Delimiter$)
  159. '----------------------------------------------------------
  160. '-- Returns: True as long as we don't bomb out due to
  161. '              a delimiter or String not being passed.
  162. '            ERR_ITEMS_TRUNCATED(-2) if we try to load more
  163. '              elements than exist in the array. If this is
  164. '              the case then some elements will have been
  165. '              loaded properly but some may have been
  166. '              truncated.
  167. '
  168. '-- StringIn$ = The string to parse
  169. '   arrOut$() = The array to fill (should be dynamic as
  170. '               it will be ReDim'ed in this procedure)
  171. '   Delimiter$= The character(s) separating the elements
  172. '               in Stringin$
  173. '----------------------------------------------------------
  174.     Dim LastItemPos%, NextItemPos%
  175.     Dim StartPos%
  176.     Dim ItemLen%
  177.     Dim DelimiterLength%
  178.     Dim NumItems%
  179.     Dim ItemNum%
  180.     Dim bGetLastItem%
  181.     
  182.     
  183.     If Len(StringIn$) = 0 Then
  184.         ddeParseString% = False
  185.         Exit Function
  186.     End If
  187.  
  188.     DelimiterLength% = Len(Delimiter$)
  189.     If DelimiterLength% = 0 Then
  190.         ddeParseString% = False
  191.         Exit Function
  192.     End If
  193.  
  194.     '@tlh
  195.     'StringIn$ = Trim(StringIn$)
  196.  
  197.     'On Error Resume Next
  198.     On Error GoTo ErrParse
  199.         '-----------------------------------------------------
  200.         '-- First time through we're just counting
  201.         '-----------------------------------------------------
  202.         NextItemPos% = InStr(StringIn$, Delimiter$)
  203.         While NextItemPos%
  204.             NumItems% = NumItems% + 1
  205.             StartPos% = NextItemPos% + DelimiterLength%
  206.             NextItemPos% = InStr(StartPos%, StringIn$, Delimiter$)
  207.         Wend
  208.         
  209.         '-----------------------------------------------------
  210.         '-- We now know how many items are in the string so
  211.         '   we can initialize our array. The exception to this
  212.         '   would be if the Delimiter is the last thing in the
  213.         '   string in which case we need to ReDim to one less
  214.         '   item than we counted.
  215.         '-----------------------------------------------------
  216.         If StartPos% <> Len(StringIn$) + 1 Then
  217.             ReDim arrOut$(NumItems%)
  218.             '-- Set a flag so we know to get the last element
  219.             bGetLastItem% = True
  220.         Else 'The string ended in with the delimiter :@tlh
  221.             '@Issue:tlh  revise this code later.  Would be better
  222.             '            to repeatedly trim delimiter off end of
  223.             '            string until it's gone.
  224.             '@:tlh Seems to be a logic error later on in loading the
  225.             '   array, so I will fix by cutting delimiter off
  226.             '   the end of the string and in effect normalizing these
  227.             '   two cases to a single one.
  228.             ReDim arrOut$(NumItems% - 1)
  229.             StringIn$ = Mid$(StringIn$, 1, (Len(StringIn$) - DelimiterLength%))
  230.             bGetLastItem% = True
  231.         End If
  232.  
  233.         '-- This needs to be initialized
  234.         LastItemPos% = 1
  235.         
  236.         '-----------------------------------------------------
  237.         '-- Now it's for real. Get the items from the string.
  238.         '-----------------------------------------------------
  239.         NextItemPos% = InStr(StringIn$, Delimiter$)
  240.         While NextItemPos%
  241.             StartPos% = LastItemPos%
  242.             ItemLen% = (NextItemPos% - LastItemPos%)
  243.             
  244.             arrOut$(ItemNum%) = Mid$(StringIn$, StartPos%, ItemLen%)
  245.             ItemNum% = ItemNum% + 1
  246.             '
  247.             If ItemNum% > UBound(arrOut$) Then
  248.                 ddeParseString% = ERR_ITEMS_TRUNCATED
  249.                 Exit Function
  250.             End If
  251.             
  252.             LastItemPos% = NextItemPos% + DelimiterLength%
  253.             NextItemPos% = InStr(LastItemPos%, StringIn$, Delimiter$)
  254.         Wend
  255.  
  256.         '-- If the bGetLastItem% flag is on then
  257.         '   we have one more element to get.
  258.         If bGetLastItem% Then
  259.             arrOut$(ItemNum%) = Mid$(StringIn$, LastItemPos%)
  260.         End If
  261.     
  262.     'On Error GoTo 0
  263.  
  264.     ddeParseString% = True
  265.  
  266. Exit Function
  267.  
  268. ErrParse:
  269.    MsgBox "Error: " & Str$(Err) & " : " & Error$
  270.    Exit Function
  271.  
  272.  
  273. End Function
  274.  
  275.  
  276. Function ddepmGetGroupFiles% (txtLink As TextBox, arrGroups$(), arrGroupFiles$())
  277.    Dim PrevLinkTimeout%
  278.    Dim PropertyDelimiter$
  279.    Dim GroupItemInfo$
  280.    Dim i%
  281.    Dim myStartPos%
  282.    Dim myEndPos%
  283.    Dim myGrpFile$
  284.    ReDim arrGroupFiles$(UBound(arrGroups$))  'We expect same number of files
  285.    
  286.    On Error GoTo myddepmGroupInfoError
  287.  
  288.    'Initialize Variables
  289.    PropertyDelimiter$ = Chr$(44)  ' Comma ","
  290.    
  291.    'Preserve previous Link settings
  292.    PrevLinkTimeout% = txtLink.LinkTimeout
  293.    
  294.    If UBound(arrGroups$) = 0 Then 'this is an empter array!
  295.       ddepmGetGroupFiles% = False  'function failed, nothing to process
  296.       Exit Function
  297.    End If
  298.    
  299.    'Establish DDE Link settings
  300.    txtLink.LinkTopic = "ProgMan|Progman"  'program manager is the link topic.
  301.    txtLink.LinkMode = LINK_MANUAL
  302.    txtLink.LinkTimeout = 100
  303.    
  304.    'Ask progman for group info for each group name in the arrGroups$ array
  305.    For i% = 0 To UBound(arrGroups$)
  306.       txtLink.LinkTopic = "ProgMan|Progman"  'program manager is the link topic.
  307.       txtLink.LinkMode = LINK_MANUAL
  308.       txtLink.LinkTimeout = 100
  309.       txtLink.LinkItem = arrGroups$(i%)      'group name to retrieve info for.
  310.       txtLink.LinkRequest                    'returned in txtLink.Text
  311.       GroupItemInfo$ = txtLink.Text
  312.       
  313.       'second entry in delimited list is the fully qualified group file name.
  314.       myStartPos% = (InStr(1, GroupItemInfo$, PropertyDelimiter$)) + 1
  315.       myEndPos% = InStr(myStartPos%, GroupItemInfo$, PropertyDelimiter$)
  316.       myGrpFile$ = Mid$(GroupItemInfo$, myStartPos%, myEndPos% - myStartPos%)
  317.       
  318.       'extract the file name only and load into arrGroupFiles$ array.
  319.       arrGroupFiles$(i%) = ExtractName$(myGrpFile$, False)
  320.       Debug.Print Str$(i%) & " : " & arrGroupFiles$(i%)
  321.    Next
  322.          
  323.    '---------------------------------------------------------
  324.    'Reset DDE Link properties
  325.    '---------------------------------------------------------
  326.    txtLink.LinkTimeout = PrevLinkTimeout%
  327.    txtLink.LinkMode = 0
  328.  
  329.  
  330. ddepmGetGroupFiles% = True
  331. Exit Function
  332.  
  333. myddepmGroupInfoError:
  334.    MsgBox "Problem retrieving program group information." & Chr$(10) & Chr$(13) & "Error num: " & Str$(Err) & Chr$(10) & Chr$(13) & "  Error is: " & Error$
  335.    ddepmGetGroupFiles% = False  'function failed
  336.    Exit Function
  337.  
  338. End Function
  339.  
  340. Function ddepmGetGroups% (txtLink As TextBox, arrGroups$())
  341. 'txtLink As TextBox
  342. '---------------------------------------------------------
  343. '-- Returns: True if all goes well.
  344. '            False if any DDE errors occur. If this is the
  345. '             case then no group names will have been
  346. '             loaded.
  347. '            ERR_ITEMS_TRUNCATED(-2) if an error occurs
  348. '             while parsing the Group Names.
  349. '
  350. '-- NOTE:    Even if errors occur(-2) some GroupNames may
  351. '            have been loaded successfully into the array.
  352. '
  353. '-- Returns arrGroups$() filled with all the available
  354. '   groups in ProgMan. The array is 0 based so the calling
  355. '   procedure should read from 0 to Ubound(arrGroups$) -1
  356. '   in order to read all the group names.
  357. '
  358. '-- arrGroups$() should be a dynamic string array. This
  359. '   procedure will resize it as necessary.
  360. '---------------------------------------------------------
  361.     Dim i%
  362.     Dim OldLinkTimeout%
  363.     Dim GroupList$
  364.     Dim Delimiter$
  365.     Dim NumGroups%
  366.     Dim CRLFPos%
  367.     Dim GroupsParsedOK%
  368.  
  369.     OldLinkTimeout% = txtLink.LinkTimeout
  370.  
  371.     '---------------------------------------------------------
  372.     '-- Set LinkTopic to PROGRAM MANAGER
  373.     '---------------------------------------------------------
  374.     txtLink.LinkTopic = "ProgMan|Progman"
  375.     txtLink.LinkMode = LINK_MANUAL
  376.     txtLink.LinkTimeout = 100
  377.     
  378.     On Error GoTo myddepmGetGroupsError
  379.         '---------------------------------------------------------
  380.         '-- Ask for the program manager group information
  381.         '   (returned in txtLink.text)
  382.         '---------------------------------------------------------
  383.         txtLink.LinkItem = "PROGMAN"
  384.         txtLink.LinkRequest
  385.         
  386.         '-- Set return value
  387.         GroupList$ = txtLink.Text
  388.  
  389.     On Error GoTo 0
  390.  
  391.     '---------------------------------------------------------
  392.     '-- Reset properties
  393.     '---------------------------------------------------------
  394.     txtLink.LinkTimeout = OldLinkTimeout%
  395.     txtLink.LinkMode = 0
  396.         
  397.  
  398.     '---------------------------------------------------------
  399.     '-- Load the array with the names of the groups
  400.     '---------------------------------------------------------
  401.     Delimiter$ = Chr$(13) & Chr$(10)
  402.     GroupsParsedOK% = ddeParseString%(GroupList$, arrGroups$(), Delimiter$)
  403.     If GroupsParsedOK% = True Then
  404.         ddepmGetGroups% = True
  405.     ElseIf GroupsParsedOK% = ERR_ITEMS_TRUNCATED Then
  406.         ddepmGetGroups% = ERR_ITEMS_TRUNCATED
  407.     End If
  408.  
  409.  
  410. myddepmGetGroupsExit:
  411.     Screen.MousePointer = DEFAULT
  412.     On Error GoTo 0
  413.     Exit Function
  414.  
  415.  
  416. myddepmGetGroupsError:
  417.     ddepmGetGroups% = False
  418.     MsgBox "An error occured in retrieving program manager group names." & Chr$(10) & Chr$(13) & "Error: " & Error$
  419.     Resume myddepmGetGroupsExit
  420.  
  421.  
  422. End Function
  423.  
  424. Function ddeSetGroupNameToUse% (arrGroups$(), arrGroupFiles$(), grpName$, grpFile$)
  425.    Dim i%
  426.    Dim arraySize%
  427.    Dim ffound%  'flag
  428.    
  429.    On Error GoTo ErmySetGroupNameToUse
  430.    
  431.    'Initialize variables
  432.    arraySize% = UBound(arrGroups$)
  433.    ffound% = False
  434.    
  435.    
  436.    i% = -1
  437.    While (Not (ffound%)) And (i% < arraySize%)
  438.       i% = i% + 1
  439.       If (arrGroups$(i%) = grpName$) Or (UCase$(grpFile$ & ".GRP") = UCase$(arrGroupFiles$(i%))) Then
  440.          ffound% = True
  441.          grpName$ = arrGroups$(i%)
  442.       End If
  443.    Wend
  444.    '
  445.    
  446.    
  447.    
  448. Exit Function
  449. ErmySetGroupNameToUse:
  450.    MsgBox "Error: " & Str$(Err) & " : " & Error$
  451.    Exit Function
  452.  
  453. End Function
  454. '>>>>>>>>>>>>>>>>>>>>>>>End DDE.BAS
  455.  
  456.